/********************************************************************************
*                                                                               *
* kWookaProjectInfo.cpp -- The data struct definition                           *
*                                                                               *
* Copyright (c) Fengren Technology(Guangzhou) Co.LTD. All rights reserved.      *
*                                                                               *
********************************************************************************/

#include "kWookaProjectInfo.hpp"
#include <wx/arrimpl.cpp>
#include "wx/file.h"
#include "cJSON.h"

#include "kWookaExecuteProcess.hpp"
#include "kWookaToolsExecuteProcess.hpp"
#include "kWooka_perferences_utils.hpp"

WX_DEFINE_OBJARRAY(kWookaAppConfigArray);

WX_DEFINE_OBJARRAY(kWookaAppArray);

WX_DEFINE_OBJARRAY(kWookaMavenRepoArray);

int wxCMPFUNC_CONV OrderBySort(kWookaAppItemInfo** p1, kWookaAppItemInfo** p2) {
	if (p1 != NULL && p2 != NULL) {
		kWookaAppItemInfo* t1 = *p1;
		kWookaAppItemInfo* t2 = *p2;
		if (t1 != NULL && t2 != NULL) {
			return t1->sort > t2->sort ? 1 : -1;
		}
	}
	return 0;
}


void kWookaProjectInfo::Load(const wxString& path) {
	wxFile file;
	if (file.Open(path, wxFile::read)) {
		// file.Write(wxString(buff));
		wxString text;
		file.ReadAll(&text);
		cJSON* json = cJSON_Parse(text.c_str());
		cJSON* pn = cJSON_GetObjectItem(json, "projectName");
		cJSON* ws = cJSON_GetObjectItem(json, "workspace");
		cJSON* mv = cJSON_GetObjectItem(json, "mavenHome");
		if (pn != NULL) {
			// 
		}
		if (ws != NULL) {
			this->workspace = ws->valuestring;
		}
		if (mv != NULL) {
			this->mavenHome = mv->valuestring;
		}

		this->fromJSON(json);

		cJSON_Delete(json);
	}
}

void kWookaProjectInfo::fromJSON(cJSON* json) {

	cJSON* jvmVal = cJSON_GetObjectItem(json, "globalJvmConfig");
	if (jvmVal != NULL) {
		cJSON* val2 = cJSON_GetObjectItem(jvmVal, "heap");
		if (val2 != NULL) {
			this->jvmConfig.jvmHeap = val2->valuestring;
		}
		val2 = cJSON_GetObjectItem(jvmVal, "maxHeap");
		if (val2 != NULL) {
			this->jvmConfig.jvmMaxHeap = val2->valuestring;
		}
		val2 = cJSON_GetObjectItem(jvmVal, "maxPermSize");
		if (val2 != NULL) {
			this->jvmConfig.jvmMaxPermSize = val2->valuestring;
		}
		val2 = cJSON_GetObjectItem(jvmVal, "maxDirectMemorySize");
		if (val2 != NULL) {
			this->jvmConfig.jvmMaxDirectMemorySize = val2->valuestring;
		}
		val2 = cJSON_GetObjectItem(jvmVal, "gcOptions");
		if (val2 != NULL) {
			this->jvmConfig.jvmGCOptions = val2->valuestring;
		}
		val2 = cJSON_GetObjectItem(jvmVal, "otherOptions");
		if (val2 != NULL) {
			this->jvmConfig.jvmGCOptions = val2->valuestring;
		}
		val2 = cJSON_GetObjectItem(jvmVal, "jdkHome");
		if (val2 != NULL) {
			this->jvmConfig.jdkHome = val2->valuestring;
		}
	}

	cJSON* appVals = cJSON_GetObjectItem(json, "globalAppConfig");

	if (appVals != NULL) {
		int jsonSize = cJSON_GetArraySize(appVals);
		for (int i = 0; i < jsonSize; i++) {
			cJSON* jit = cJSON_GetArrayItem(appVals, i);
			if (jit != NULL) {
				cJSON* k = cJSON_GetObjectItem(jit, "key");
				cJSON* v = cJSON_GetObjectItem(jit, "value");
				cJSON* t = cJSON_GetObjectItem(jit, "type");
				if (k != NULL && v != NULL) {
					kWookaAppConfigItemInfo itm;
					itm.configKey = k->valuestring;
					itm.configValue = v->valuestring;
					if (t != NULL) {
						itm.configType = t->valuestring;
					}
					this->appConfigs.Add(itm);
				}
			}
		}
	}

	cJSON* mavenRepos = cJSON_GetObjectItem(json, "mavenRepositories");
	if (mavenRepos != NULL) {
		int jsonSize = cJSON_GetArraySize(mavenRepos);
		for (int i = 0; i < jsonSize; i++) {
			cJSON* jit = cJSON_GetArrayItem(mavenRepos, i);
			if (jit != NULL) {
				cJSON* k = cJSON_GetObjectItem(jit, "repoId");
				cJSON* v = cJSON_GetObjectItem(jit, "address");
				cJSON* t = cJSON_GetObjectItem(jit, "snapshot");
				if (k != NULL && v != NULL) {
					kWookaMavenRepoInfo itm;
					itm.repoId = k->valuestring;
					itm.address = v->valuestring;
					if (t != NULL) {
						itm.snapshot = t->valuestring;
					}
					this->mavenRepositories.Add(itm);
				}
			}
		}
	}

	cJSON* apps = cJSON_GetObjectItem(json, "applications");
	if (apps != NULL) {
		int jsonSize = cJSON_GetArraySize(apps);
		for (int i = 0; i < jsonSize; i++) {
			cJSON* jit = cJSON_GetArrayItem(apps, i);
			kWookaAppItemInfo app;
			app.fromJSONObject(jit);
			this->Applications.Add(app);
		}
		this->Applications.Sort(OrderBySort);
	}
	
}

void kWookaProjectInfo::Save(const wxString& path) {
	cJSON* root = cJSON_CreateObject();
	cJSON_AddItemToObject(root, "projectName", cJSON_CreateString("kWooka"));
	cJSON_AddItemToObject(root, "workspace", cJSON_CreateString(workspace));
	cJSON_AddItemToObject(root, "mavenHome", cJSON_CreateString(mavenHome));
	cJSON* jvm = cJSON_CreateObject();
	cJSON_AddItemToObject(jvm, "heap", cJSON_CreateString(this->jvmConfig.jvmHeap));
	cJSON_AddItemToObject(jvm, "maxHeap", cJSON_CreateString(this->jvmConfig.jvmMaxHeap));
	cJSON_AddItemToObject(jvm, "maxPermSize", cJSON_CreateString(this->jvmConfig.jvmMaxPermSize));
	cJSON_AddItemToObject(jvm, "maxDirectMemorySize", cJSON_CreateString(this->jvmConfig.jvmMaxDirectMemorySize));
	cJSON_AddItemToObject(jvm, "gcOptions", cJSON_CreateString(this->jvmConfig.jvmGCOptions));
	cJSON_AddItemToObject(jvm, "otherOptions", cJSON_CreateString(this->jvmConfig.jvmOtherOptions));
	cJSON_AddItemToObject(jvm, "jdkHome", cJSON_CreateString(this->jvmConfig.jdkHome));
	
	cJSON_AddItemToObject(root, "globalJvmConfig", jvm);

	cJSON* cfgs = cJSON_CreateArray();
	for (size_t s = 0; s < this->appConfigs.Count(); s++) {
		kWookaAppConfigItemInfo& it = appConfigs[s];
		cJSON* cfgItem = cJSON_CreateObject();
		cJSON_AddItemToObject(cfgItem, "key", cJSON_CreateString(it.configKey));
		cJSON_AddItemToObject(cfgItem, "value", cJSON_CreateString(it.configValue));
		cJSON_AddItemToObject(cfgItem, "type", cJSON_CreateString(it.configType));
		cJSON_AddItemToArray(cfgs, cfgItem);
	}

	cJSON_AddItemToObject(root, "globalAppConfig", cfgs);

	cJSON* mvn = cJSON_CreateArray();
	for (size_t s = 0; s < this->mavenRepositories.Count(); s++) {
		kWookaMavenRepoInfo& it = mavenRepositories[s];
		cJSON* cfgItem = cJSON_CreateObject();
		cJSON_AddItemToObject(cfgItem, "repoId", cJSON_CreateString(it.repoId));
		cJSON_AddItemToObject(cfgItem, "address", cJSON_CreateString(it.address));
		cJSON_AddItemToObject(cfgItem, "snapshot", cJSON_CreateString(it.snapshot));
		cJSON_AddItemToArray(mvn, cfgItem);
	}

	cJSON_AddItemToObject(root, "mavenRepositories", mvn);

	cJSON* apps = cJSON_CreateArray();
	
	for (size_t s = 0; s < this->Applications.Count(); s++) {
		kWookaAppItemInfo& it = Applications[s];
		cJSON* appItem = it.toJSONObject();
		cJSON_AddItemToArray(apps, appItem);
	}

	cJSON_AddItemToObject(root, "applications", apps);
	char* buff = cJSON_Print(root);
	wxFile file;
	if (file.Open(path, wxFile::write)) {
		file.Write(wxString(buff));
	}
	cJSON_Delete(root);
}


/**
 * kWookaAppItemInfo
 */

cJSON* kWookaAppItemInfo::toJSONObject() {
	cJSON* root = cJSON_CreateObject();
	cJSON_AddItemToObject(root, "id", cJSON_CreateString(this->id));
	cJSON_AddItemToObject(root, "source", cJSON_CreateString(this->source));
	cJSON_AddItemToObject(root, "name", cJSON_CreateString(this->name));
	cJSON_AddItemToObject(root, "appType", cJSON_CreateString(this->appType));
	cJSON_AddItemToObject(root, "description", cJSON_CreateString(this->description));
	cJSON_AddItemToObject(root, "groupId", cJSON_CreateString(this->groupId));
	cJSON_AddItemToObject(root, "version", cJSON_CreateString(this->version));
	cJSON_AddItemToObject(root, "startClass", cJSON_CreateString(this->startClass));
	cJSON_AddItemToObject(root, "sort", cJSON_CreateNumber(this->sort));

	cJSON* jvm = cJSON_CreateObject();
	cJSON_AddItemToObject(jvm, "heap", cJSON_CreateString(this->jvmConfig.jvmHeap));
	cJSON_AddItemToObject(jvm, "maxHeap", cJSON_CreateString(this->jvmConfig.jvmMaxHeap));
	cJSON_AddItemToObject(jvm, "maxPermSize", cJSON_CreateString(this->jvmConfig.jvmMaxPermSize));
	cJSON_AddItemToObject(jvm, "maxDirectMemorySize", cJSON_CreateString(this->jvmConfig.jvmMaxDirectMemorySize));
	cJSON_AddItemToObject(jvm, "gcOptions", cJSON_CreateString(this->jvmConfig.jvmGCOptions));
	cJSON_AddItemToObject(jvm, "otherOptions", cJSON_CreateString(this->jvmConfig.jvmOtherOptions));
	cJSON_AddItemToObject(jvm, "jdkHome", cJSON_CreateString(this->jvmConfig.jdkHome));
	cJSON_AddItemToObject(jvm, "debugAddress", cJSON_CreateString(this->jvmConfig.jvmDebugAddress));
	if (this->jvmConfig.jvmDebugEnabled) {
		cJSON_AddItemToObject(jvm, "debugEnabled", cJSON_CreateString("true"));
	}
	else {
		cJSON_AddItemToObject(jvm, "debugEnabled", cJSON_CreateString("false"));
	}

	cJSON_AddItemToObject(root, "jvmConfig", jvm);

	cJSON* cfgs = cJSON_CreateArray();
	for (size_t s = 0; s < this->appConfigs.Count(); s++) {
		kWookaAppConfigItemInfo& it = appConfigs[s];
		cJSON* cfgItem = cJSON_CreateObject();
		cJSON_AddItemToObject(cfgItem, "key", cJSON_CreateString(it.configKey));
		cJSON_AddItemToObject(cfgItem, "value", cJSON_CreateString(it.configValue));
		cJSON_AddItemToObject(cfgItem, "type", cJSON_CreateString(it.configType));
		cJSON_AddItemToArray(cfgs, cfgItem);
	}

	cJSON_AddItemToObject(root, "appConfigs", cfgs);

	cJSON* libs = cJSON_CreateArray();
	for (size_t s = 0; s < this->libraries.Count(); s++) {
		wxString& text = libraries[s];
		cJSON* textItem = cJSON_CreateString(text);
		cJSON_AddItemToArray(libs, textItem);
	}
	cJSON_AddItemToObject(root, "libraries", libs);

	return root;
}

void kWookaAppItemInfo::fromJSONObject(cJSON* json) {
	cJSON* val = cJSON_GetObjectItem(json, "name");
	if (val != NULL) {
		this->name = val->valuestring;
	}
	val = cJSON_GetObjectItem(json, "id");
	if (val != NULL) {
		this->id = val->valuestring;
	}
	else {
		this->id = wxNewGuid();
	}
	val = cJSON_GetObjectItem(json, "source");
	if (val != NULL) {
		this->source = val->valuestring;
	}
	val = cJSON_GetObjectItem(json, "appType");
	if (val != NULL) {
		this->appType = val->valuestring;
	}
	val = cJSON_GetObjectItem(json, "description");
	if (val != NULL) {
		this->description = val->valuestring;
	}
	val = cJSON_GetObjectItem(json, "groupId");
	if (val != NULL) {
		this->groupId = val->valuestring;
	}
	val = cJSON_GetObjectItem(json, "version");
	if (val != NULL) {
		this->version = val->valuestring;
	}
	val = cJSON_GetObjectItem(json, "startClass");
	if (val != NULL) {
		this->startClass = val->valuestring;
	}
	val = cJSON_GetObjectItem(json, "sort");
	if (val != NULL) {
		this->sort = val->valueint;
		if (val->valueint == 0 && val->valuestring != NULL) {
			this->sort = atoi(val->valuestring);
		}
	}

	cJSON* jvmVal = cJSON_GetObjectItem(json, "jvmConfig");
	if (jvmVal != NULL) {
		cJSON* val2 = cJSON_GetObjectItem(jvmVal, "heap");
		if (val2 != NULL) {
			this->jvmConfig.jvmHeap = val2->valuestring;
		}
		val2 = cJSON_GetObjectItem(jvmVal, "maxHeap");
		if (val2 != NULL) {
			this->jvmConfig.jvmMaxHeap = val2->valuestring;
		}
		val2 = cJSON_GetObjectItem(jvmVal, "maxPermSize");
		if (val2 != NULL) {
			this->jvmConfig.jvmMaxPermSize = val2->valuestring;
		}	
		val2 = cJSON_GetObjectItem(jvmVal, "maxDirectMemorySize");
		if (val2 != NULL) {
			this->jvmConfig.jvmMaxDirectMemorySize = val2->valuestring;
		}
		
		val2 = cJSON_GetObjectItem(jvmVal, "gcOptions");
		if (val2 != NULL) {
			this->jvmConfig.jvmGCOptions = val2->valuestring;
		}
		val2 = cJSON_GetObjectItem(jvmVal, "otherOptions");
		if (val2 != NULL) {
			this->jvmConfig.jvmGCOptions = val2->valuestring;
		}
		val2 = cJSON_GetObjectItem(jvmVal, "jdkHome");
		if (val2 != NULL) {
			this->jvmConfig.jdkHome = val2->valuestring;
		}
		val2 = cJSON_GetObjectItem(jvmVal, "debugAddress");
		if (val2 != NULL) {
			this->jvmConfig.jvmDebugAddress = val2->valuestring;
		}
		val2 = cJSON_GetObjectItem(jvmVal, "debugEnabled");
		if (val2 != NULL) {
			wxString tt = val2->valuestring;
			this->jvmConfig.jvmDebugEnabled = tt.compare(wxT("true")) == 0;
		}
		else {
			this->jvmConfig.jvmDebugEnabled = false;
		}
	}

	cJSON* appVals = cJSON_GetObjectItem(json, "appConfigs");

	if (appVals != NULL) {
		int jsonSize = cJSON_GetArraySize(appVals);
		for (int i = 0; i < jsonSize; i++) {
			cJSON* jit = cJSON_GetArrayItem(appVals, i);
			if (jit != NULL) {
				cJSON* k = cJSON_GetObjectItem(jit, "key");
				cJSON* v = cJSON_GetObjectItem(jit, "value");
				cJSON* t = cJSON_GetObjectItem(jit, "type");
				if (k != NULL && v != NULL) {
					kWookaAppConfigItemInfo itm;
					itm.configKey = k->valuestring;
					itm.configValue = v->valuestring;
					if (t != NULL) {
						itm.configType = t->valuestring;
					}
					this->appConfigs.Add(itm);
				}
			}
		}
	}

	cJSON* libs = cJSON_GetObjectItem(json, "libraries");
	if (libs != NULL) {
		int jsonSize = cJSON_GetArraySize(libs);
		for (int i = 0; i < jsonSize; i++) {
			cJSON* jit = cJSON_GetArrayItem(libs, i);
			if (jit != NULL) {
				this->libraries.Add(jit->valuestring);
			}
		}
	}
	
}

const wxString kWookaAppItemInfo::DEFAULT_EMPTY_STRING = wxString(wxT(""));

void kWookaAppItemInfo::UpdateItem(const wxString& key, const wxString& value, const wxString& type) {
	for (size_t t = 0; t < this->appConfigs.Count(); t++) {
		kWookaAppConfigItemInfo& item = appConfigs[t];
		if (item.configKey == key) {
			item.configValue = value;
			item.configType = type;
			return;
		}
	}

	kWookaAppConfigItemInfo it;
	it.configKey = key;
	it.configType = type;
	it.configValue = value;
	appConfigs.Add(it);
}

bool kWookaAppItemInfo::ItemExist(const wxString& key) {
	for (size_t t = 0; t < this->appConfigs.Count(); t++) {
		kWookaAppConfigItemInfo& item = appConfigs[t];
		if (item.configKey == key) {
			return true;
		}
	}
	return false;
}

const wxString& kWookaAppItemInfo::GetItemValue(const wxString& key) {
	for (size_t t = 0; t < this->appConfigs.Count(); t++) {
		kWookaAppConfigItemInfo& item = appConfigs[t];
		if (item.configKey == key) {
			return item.configValue;
		}
	}
	return kWookaAppItemInfo::DEFAULT_EMPTY_STRING;
}


void kWookaAppItemInfo::AddLibrary(const wxString& lib) {
	if (this->libraries.Index(lib) == wxNOT_FOUND) {
		libraries.Add(lib);
	}
}

void kWookaAppItemInfo::DelLibrary(const wxString& lib) {	
	libraries.Remove(lib);
}





/*
 * kWookaProjectRuntimeInfo implementatios
 */
kWookaProcessExecutor* kWookaProjectRuntimeInfo::CreateExecutor(kWookaAppItemInfo* appitem) {
	kWookaProcessExecutor* executor = new kWookaProcessExecutor();
	executor->Create(m_project, appitem);
	if (appitem->appType == wxT("maven")) {
		executor->SetProcessFactory(new kWookaMavenExecutorFactory());
	}
	else if (appitem->appType == wxT("redis")) {
		executor->SetProcessFactory(new kWookaRedisExecutorFactory());
	}
	else if (appitem->appType == wxT("mysql")) {
		executor->SetProcessFactory(new kWookaMySQLExecutorFactory());
	}
	else if (appitem->appType == wxT("nginx-server") || appitem->appType == wxT("nginx")) {
		executor->SetProcessFactory(new kWookaNginxExecutorFactory());
	}
	else if (appitem->appType == wxT("java")) {
		executor->SetProcessFactory(new kWookaGenericJavaExecutorFactory());
	}
	executeMap[appitem->id] = executor;
	return executor;
}


kWookaProcessExecutor* kWookaProjectRuntimeInfo::GetExecutor(const wxString& app) {
	kWookaProcessExecutor* exec = executeMap[app];
	if (exec == NULL) {
		for (size_t ii = 0; ii < m_project->Applications.Count(); ii++) {
			kWookaAppItemInfo& item = m_project->Applications[ii];
			if (app == item.id) {
				exec = this->CreateExecutor(&item);
				break;
			}
		}
	}
	return exec;
}

wxVector<kWookaProcessExecutor*> kWookaProjectRuntimeInfo::GetAllExecutors() {
	wxVector<kWookaProcessExecutor*> vect;
	for (kWookaExecutorMap::const_iterator it = executeMap.begin(); it != executeMap.end(); ++it) {
		vect.push_back(it->second);
	}
	return vect;
}

void kWookaProjectRuntimeInfo::Clear() {
	for (kWookaExecutorMap::const_iterator it = executeMap.begin(); it != executeMap.end(); ++it) {
		kWookaProcessExecutor* exectuor = static_cast<kWookaProcessExecutor*>(it->second);
		if (exectuor != NULL) {
			delete exectuor;
		}
	}
	executeMap.clear();
}

bool kWookaProjectRuntimeInfo::IsRunning() {
	for (kWookaExecutorMap::const_iterator it = executeMap.begin(); it != executeMap.end(); ++it) {
		if (it->second->IsStarted()) {
			return true;
		}
	}

	return false;
}
